# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
#define BUFFER_SIZE 5

//empty  同步信号量，表示剩余空间的数量
// full 同步信号量，表示产品的数量
// mutex 互斥信号量，实现对缓冲区的互斥访问
sem_t empty, full, mutex;

typedef int buffer_item;

//缓冲区
buffer_item buffer[BUFFER_SIZE];

int in, out;

// 记录产品的id
int id = 0;

int insert_item(buffer_item item) {
    //插入产品
    buffer[out] = item;
    out = (out + 1) % BUFFER_SIZE;
    return 0;
}

//有限缓存删除--消费
int remove_item(buffer_item *item) {
    // 将buffer[in]移除，并将item填充进去
    *item = buffer[in];
    in = (in + 1) % BUFFER_SIZE;
    return 0;
}

//生产者
void *producer(void* param) {
    while (1){
        sem_wait(&empty);
        sem_wait(&mutex);
        //生产产品
        insert_item(id);
        //单位为秒
        sleep(5);
        printf("ThreadId %d : Producer produce productId -> %d \n", pthread_self(),id);
        id++;
        sem_post(&mutex);
        sem_post(&full);
    }
    pthread_exit(0);
}

//消费者
void *consumer(void* param) {
    while (1){
        sem_wait(&full);
        sem_wait(&mutex);
        //消费产品
        int item;
        remove_item(&item);
        sleep(3);
        printf("ThreadId %d : Consumer consume productId -> %d \n", pthread_self(),item);
        sem_post(&mutex);
        sem_post(&empty);
    }
    pthread_exit(0);
}
void getProperty(pthread_attr_t attr){
    int ret;
    //并发级别
    int level;
    ret = pthread_getconcurrency();
    if(0 != ret) {
        printf("pthread_getconcurrency error \n");
    } else {
        printf("pthread_getconcurrency: %d\n", level);
    }
    //线程优先级
    int priority;
    ret = pthread_attr_getschedparam(&attr,&priority);
    if(0 != ret) {
        printf("pthread_attr_getschedparam  error \n");
    } else {
        printf("pthread_attr_getschedparam : priority %d\n", priority);
    }
    //线程的调度策略
    int policy;
    ret = pthread_attr_getschedpolicy(&attr, &policy);
    if(0 != ret) {
        printf("pthread_attr_getschedpolicy error\n");
    }
    else {
        if(SCHED_FIFO == policy)
            //先来先服务
            printf("pthread_attr_getschedpolicy: SCHED_FIFO\n");
        else if(SCHED_RR == policy)
            //时间片轮转
            printf("pthread_attr_getschedpolicy: SCHED_RR\n");
        else if(SCHED_OTHER == policy)
            //其他
            printf("pthread_attr_getschedpolicy: SCHED_OTHER\n");
    }
    //线程栈大小
    size_t size;
    ret = pthread_attr_getstacksize(&attr, &size);
    if(0 != ret) {
        printf("pthread_attr_getstacksize error");
    } else {
        printf("pthread_attr_getstacksize: %lu\n", size);
    }
    //线程的作用域
    int scope;
    ret = pthread_attr_getscope(&attr, &scope);
    if(0 != ret) {
        printf("pthread_attr_getscope error");
    } else {
//        非绑定的
        if(PTHREAD_SCOPE_PROCESS == scope)
            printf("pthread_attr_getscope: PTHREAD_SCOPE_PROCESS\n");
        //        绑定的线程  被绑定的线程具有较高的响应速度
        else if(PTHREAD_SCOPE_SYSTEM == scope)
            printf("pthread_attr_getscope: PTHREAD_SCOPE_SYSTEM\n");
    }
}
void choiceMenu(){
    printf("选择一种情况：\n");
    printf("1.缓冲区满，生产者到达\n"
           "2.缓冲区满，消费者到达\n"
           "3.缓冲区空，生产者到达\n"
           "4.缓冲区空，消费者到达\n"
           "5.缓冲区空，生产者消费者同时运行\n"
           "6.退出\n");
}

int main() {
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    //设置调度方式为先来先服务
        pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
//    对mutex进行初始化
    //第二个参数 不为０时此信号量在进程间共享，否则只能为当前进程的所有线程共享
    //第三个参数 给出了信号量的初始值。　　
    sem_init(&mutex, 0, 1);
    sem_init(&empty, 0, BUFFER_SIZE);
    sem_init(&full, 0, 0);
    in = out = 0;
    getProperty(attr);
    pthread_t pid,cid;
    //模拟几种情况
    int num;
    choiceMenu();
    while(1){
        scanf("%d",&num);
        switch(num){
            //缓冲区满，生产者到达
            case 1:
                pthread_create(&pid, &attr, producer, NULL);
                //运行30秒,缓冲区填满
                sleep(30);
                //再来一个生产者，观察
                pthread_create(&pid,&attr, producer,NULL);
                break;
            //缓冲区满，消费者到达
            case 2:
                pthread_create(&pid, &attr, producer, NULL);
                //运行30秒
                sleep(30);
                //消费者到达，进行观察
                pthread_create(&cid,&attr, consumer ,NULL);
                break;
             //缓冲区空，生产者到达
            case 3:
                //此时缓冲区为空，生产者到达
                pthread_create(&pid, &attr, producer, NULL);
                break;
            //缓冲区空，消费者到达
            case 4:
                pthread_create(&cid, &attr, consumer, NULL);
                break;
             //缓冲区空，生产者消费者同时运行
            case 5:
                pthread_create(&pid,&attr, producer,NULL);
                pthread_create(&pid,&attr, consumer,NULL);
                break;
            case 6:
                return;
        }
    }
    //释放信号量
    sem_destroy(&mutex);
    sem_destroy(&empty);
    sem_destroy(&full);
    return 0;
}

